package ffte.core.flat

import spinal.core._
import spinal.lib._

import ffte.types.VecComplex
import ffte.property.{getFFTIW,getFFTOW,FFTIOConfig}
import ffte.algorithm.FFTGen.{Method,genericFT,DFT,psbFFT,msbFFT,wpbFFT}
import ffte.core.{widthed}
import ffte.core.streamed.streamedComponents
import ffte.misc

/**
 * Flat FFT implementation method
 *
 * This class provides the core implementation method for generating flat (non-pipelined)
 * FFT hardware components from abstract algorithm specifications. The flat architecture
 * performs all FFT computation in a single clock cycle using combinatorial logic,
 * resulting in minimal latency but high resource usage.
 *
 * Architecture Characteristics:
 * - Single-cycle computation (combinatorial logic)
 * - No internal pipelining registers
 * - High resource usage but minimal latency
 * - Suitable for latency-critical applications
 * - Deterministic timing behavior
 *
 * Algorithm Support:
 * - DFT: Direct DFT implementation for small transforms
 * - psbFFT: Prime-space decomposition (Chinese Remainder Theorem based)
 * - msbFFT: Mixed-space decomposition (Cooley-Tukey based)
 * - wpbFFT: Winograd prime-based decomposition
 * - Default fallback to 2-point DFT for unknown types
 *
 * Scaling Strategy:
 * - Uses fixed-point arithmetic with configurable scaling
 * - Shift amount distributed to prevent overflow
 * - Precision managed through bit allocation
 *
 * @param shift Scaling shift amount for fixed-point overflow prevention
 */
class Flat(shift: Int) extends Method {
    /**
     * Generate flat FFT component from algorithm specification
     *
     * This method serves as the factory for creating concrete flat FFT hardware
     * components from abstract algorithm specifications. It uses pattern matching
     * to select the appropriate implementation based on the FFT algorithm type.
     *
     * Implementation Selection Logic:
     * - DFT: Direct DFT implementation for basic transforms
     * - psbFFT: Prime-space decomposition using Chinese Remainder Theorem
     * - msbFFT: Mixed-space decomposition using Cooley-Tukey algorithms
     * - wpbFFT: Winograd prime-based algorithms for optimal multiplication count
     * - Fallback: 2-point DFT for unsupported algorithm types
     *
     * @param entity Abstract FFT algorithm specification
     * @param prefix Naming prefix for generated components (for debugging/identification)
     * @return Concrete flat FFT component ready for hardware instantiation
     */
    def apply(entity: genericFT, prefix: String): flatComponents = {
        entity match {
            case d: DFT =>
                // Direct DFT implementation for small transforms or reference cases
                new ndft(d.N, shift)
            case d: psbFFT[Flat] =>
                // Prime-space decomposition (Chinese Remainder Theorem based)
                new psb(shift, d)
            case d: msbFFT[Flat] =>
                // Mixed-space decomposition (Cooley-Tukey based)
                new msb(shift, d)
            case d: wpbFFT[Flat] =>
                // Winograd prime-based decomposition (optimal multiplication count)
                new wpb(shift, d)
            case _ =>
                // Fallback to 2-point DFT for unknown algorithm types
                new ndft(2, shift)
        }
    }
  /**
     * Streaming adapter for flat FFT components
     *
     * This inner class provides a streaming interface wrapper around flat FFT components,
     * enabling the single-cycle combinatorial logic to be used in pipelined streaming
     * applications. This adapter manages flow control, data buffering, and timing
     * conversion between the flat and streaming domains.
     *
     * Architecture Conversion:
     * - Flat domain: Single-cycle combinatorial computation
     * - Streaming domain: Pipeline-based flow control
     * - Bridge: This adapter manages the domain crossing
     *
     * Flow Control Strategy:
     * - Ready signal propagation: Output ready controls input ready
     * - Valid signal generation: Output valid when computation completes
     * - Fire condition: Both ready and valid signals asserted
     * - Fragment handling: Manages data fragmentation in streaming interface
     *
     * Timing Management:
     * - Group configuration: Processes N samples as a group
     * - Delay tracking: Accounts for computation latency
     * - Last signal generation: Marks end of data bursts
     *
     * @param entity Abstract FFT algorithm specification to be converted to streaming
     * @param prefix Naming prefix for generated components
     */
    class toStreamed(entity: genericFT, prefix: String) extends streamedComponents with widthed {
        /** Group size equals transform size (process N samples together) */
        override val G = entity.N

        /** Standard streaming I/O interface */
        val io = iogen

        /**
         * Flow control: Backpressure propagation
         *
         * The output ready signal directly controls the input ready signal.
         * This creates a direct backpressure path preventing buffer overflow.
         */
        io.d.ready := io.q.ready

        /**
         * Transaction firing condition
         *
         * A transaction fires (executes) when both input valid and output ready
         * are asserted. This indicates successful data transfer.
         */
        val fire = io.d.fire

        /**
         * Output valid signal generation
         *
         * Output becomes valid when the current transaction fires.
         * This ensures output data is available and can be accepted.
         */
        io.q.valid := fire

        /**
         * Hardware implementation area with group configuration
         *
         * This area encapsulates the actual flat FFT component and manages
         * the interface between streaming and flat domains.
         */
        val gArea = FFTIOConfig(getFFTIW(),getFFTOW()) on new Area {
            /**
             * Instantiate the underlying flat FFT component
             *
             * Creates the flat FFT implementation that will perform the actual
             * mathematical computation in a single cycle.
             */
            val u = apply(entity, prefix)

            /**
             * Input data connection
             *
             * Routes the fragment data from the streaming interface to the
             * flat FFT component's input port.
             */
            u.io.d := io.d.payload.fragment

            /**
             * Output data connection
             *
             * Routes the computed results from the flat FFT component
             * to the streaming interface's fragment payload.
             */
            io.q.payload.fragment := u.io.q

            /**
             * Clock enable control
             *
             * The flat FFT component only computes when the streaming
             * transaction fires, ensuring proper timing synchronization.
             */
            u.io.ce := fire
        }

        /**
         * Component delay in clock cycles
         *
         * Returns the delay of the underlying flat FFT component,
         * representing the computational latency through the system.
         *
         * @return Delay in clock cycles
         */
        def delay = gArea.u.delay

        /**
         * Last signal generation for data burst termination
         *
         * Generates the 'last' signal that marks the end of a data burst
         * in the streaming interface. This signal is delayed to align
         * with the output data timing, accounting for the computation
         * delay through the flat FFT component.
         *
         * The delay component creates a pulse that travels through the
         * pipeline and emerges at the appropriate time to mark the final
         * sample of the current transform.
         */
        io.q.payload.last := misc.delay(delay, G).delayPulse(io.d.payload.last, fire)
    }
}

